﻿using System.Collections;

namespace DimensionsHelper.LanguageService.Syntax;

public class ArgumentList : SyntaxNode, IReadOnlyList<Expression>
{
    private SyntaxList<Expression>? _arguments;
    private SyntaxToken? _endToken;
    private SyntaxToken? _startToken;

    internal ArgumentList(SyntaxNode? parent) :
        base(SyntaxKinds.ArgumentList, parent)
    {
    }


    /// <summary>
    ///     起始符号，'(' 或 '['
    /// </summary>
    public SyntaxToken? StartToken => _startToken;


    /// <summary>
    ///     结束符号，')' 或 ']'
    /// </summary>
    public SyntaxToken? EndToken => _endToken;


    public int Count => _arguments?.Count ?? 0;


    public Expression this[int index]
    {
        get
        {
            if (_arguments == null || index < 0 || index >= _arguments.Count)
            {
                throw new IndexOutOfRangeException(nameof(index));
            }

            return _arguments[index];
        }
    }


    public IEnumerator<Expression> GetEnumerator()
    {
        return _arguments == null
            ? Enumerable.Empty<Expression>().GetEnumerator()
            : _arguments.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }


    public static bool IsNullOrEmpty(ArgumentList? argumentList)
    {
        return argumentList == null || argumentList.Count == 0;
    }


    public ArgumentList Update(SyntaxToken? startToken, SyntaxToken? endToken)
    {
        SetChildNullableField(ref _startToken, SyntaxToken.IsNullOrEmpty, startToken);
        SetChildNullableField(ref _endToken, SyntaxToken.IsNullOrEmpty, endToken);
        return this;
    }


    public ArgumentList Update(Expression argument)
    {
        _arguments ??= new SyntaxList<Expression>();
        _arguments.Add(argument);
        return this;
    }


    public override void AcceptVisitor<T>(SyntaxNodeVisitor<T> visitor)
    {
        if (_arguments != null)
        {
            AcceptList(visitor, _arguments);
        }
    }
}


public static partial class NodeFactory
{
    public static ArgumentList CreateArgumentList(SyntaxNode? parent, SyntaxToken? startToken,
        SyntaxToken? endToken, IEnumerable<Expression> args)
    {
        ArgumentList argList = new(parent);

        foreach (Expression arg in args)
        {
            argList.Update(arg);
        }

        return argList.Update(startToken, endToken);
    }
}